// benchmark.cpp
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <chrono>
#include <random>
#include <sys/stat.h> // <--- 新增头文件
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>

// 从内存中读取一个字节来触发 page fault
volatile char sink;

void create_test_file(const std::string& filename, size_t size_in_gb) {
    std::cout << "Creating test file: " << filename << " (" << size_in_gb << " GB)" << std::endl;
    std::ofstream outfile(filename, std::ios::binary);
    if (!outfile) {
        std::cerr << "Error creating file!" << std::endl;
        exit(1);
    }
    size_t total_size = size_in_gb * 1024 * 1024 * 1024;
    std::vector<char> buffer(1024 * 1024, 0); // 1MB buffer
    for (size_t i = 0; i < total_size / buffer.size(); ++i) {
        outfile.write(buffer.data(), buffer.size());
    }
    outfile.close();
    std::cout << "Test file created." << std::endl;
}

void fixed_stride_access(char* data, size_t total_size, size_t stride, size_t block_size) {
    std::cout << "Performing fixed stride access. Stride: " << stride << " bytes" << std::endl;
    for (size_t i = 0; i < total_size; i += stride) {
        // 访问块的第一个字节以触发缺页
        sink = data[i];
    }
}

int main(int argc, char* argv[]) {
    if (argc != 4) {
        std::cerr << "Usage: " << argv[0] << " <file_path> <stride_in_kb> <file_size_in_gb>" << std::endl;
        return 1;
    }

    std::string filename = argv[1];
    size_t stride_kb = std::stoul(argv[2]);
    size_t file_size_gb = std::stoul(argv[3]);

    size_t total_size = file_size_gb * 1024 * 1024 * 1024;
    size_t stride_bytes = stride_kb * 1024;
    size_t block_size = 4096; // 访问单位

    // 1. 创建大文件 (如果不存在)
    if (access(filename.c_str(), F_OK) == -1) {
        create_test_file(filename, file_size_gb);
    }

    // 2. 打开文件并 mmap

    // --- 关键修改：增加文件大小校验 ---
    int fd = open(filename.c_str(), O_RDONLY);
    if (fd == -1) {
        perror("open");
        return 1;
    }
    
    struct stat st;
    if (fstat(fd, &st) == -1) {
        perror("fstat");
        close(fd);
        return 1;
    }

    if (st.st_size < total_size) {
        std::cerr << "Error: Actual file size (" << st.st_size 
                  << ") is smaller than requested mmap size (" << total_size 
                  << "). Please check disk space or re-create the file." << std::endl;
        close(fd);
        return 1;
    }
    // --- 修改结束 ---
    char* mapped_data = (char*)mmap(NULL, total_size, PROT_READ, MAP_SHARED, fd, 0);
    if (mapped_data == MAP_FAILED) {
        perror("mmap");
        close(fd);
        return 1;
    }

    // 3. 执行访问并计时
    auto start_time = std::chrono::high_resolution_clock::now();

    fixed_stride_access(mapped_data, total_size, stride_bytes, block_size);

    auto end_time = std::chrono::high_resolution_clock::now();
    std::chrono::duration<double> elapsed = end_time - start_time;

    std::cout << "Benchmark finished." << std::endl;
    std::cout << "Total execution time: " << elapsed.count() << " seconds" << std::endl;

    // 4. 清理
    munmap(mapped_data, total_size);
    close(fd);

    return 0;
}